#include "gp_beta_server.h"
#include "sock_msg.h"
#include "msg_def.h"
#include "WingCtrlSys.grpc.pb.h"
#include <fstream>
#include "/home/hcgy/Documents/esm6800h/test/data_proc/board_data_proc.h"
using GPRPC::BarCodeParam;
using GPRPC::CtrlSysService;
using GPRPC::TakeAPictureParam;
using grpc::ClientContext;

int flagQpcrTemp = 0;
int flagQpcr1Temp = 0;

#define SET_BIT(data, bitIndex) (data = (data | (1<<bitIndex) ))

#define IS_BIT_SET(data, bitIndex) (data&(1<<bitIndex))

float qpcrTempArr[MAX_CHAN_ONE_QPCR] = {0.0};
float qpcr1TempArr[MAX_CHAN_ONE_QPCR] = {0.0};

typedef struct _qpcr_temp_report
{
   float qpcrTempArr[MAX_CHAN_ONE_QPCR];
   int flagTemp;
   int countRecv;
}qpcr_temp_report;

qpcr_temp_report qpcrTempReportArr[2];

int initQpcrTempReport(void)
{
   memset(qpcrTempReportArr,0,sizeof(qpcr_temp_report)*2);
}

//if need report, return 1;
//else return 0;
int  procQpcrTempReport(int qpcrId,int chanNum,float tempIn, float * tempArrOut)
{
      int ret = 0;
      qpcrTempReportArr[qpcrId].qpcrTempArr[chanNum] = tempIn;
      //std::cout<<"chan:"<<chanNum<<",flag:"<<std::hex<<qpcrTempReportArr[qpcrId].flagTemp<<std::endl;
      
      if(!IS_BIT_SET(qpcrTempReportArr[qpcrId].flagTemp,chanNum))
      {
         //std::cout<<"flage of chan:"<<chanNum<<"is not set"<<std::endl;
         SET_BIT(qpcrTempReportArr[qpcrId].flagTemp,chanNum);
         qpcrTempReportArr[qpcrId].countRecv ++;

         if(qpcrTempReportArr[qpcrId].countRecv>=5)
         {
            //report temp here
            memcpy(tempArrOut,qpcrTempReportArr[qpcrId].qpcrTempArr,sizeof(float)*MAX_CHAN_ONE_QPCR);
            qpcrTempReportArr[qpcrId].flagTemp = 0;
            qpcrTempReportArr[qpcrId].countRecv = 0;

            ret = 1;

         }
      }
      else
      {
          std::cout<<"flage of chan:"<<chanNum<<" is set"<<std::endl;
      }

      return ret;
}

class CtrlSysServiceClient {
 public:
  CtrlSysServiceClient(std::shared_ptr<grpc::Channel> channel)
      : stub_(CtrlSysService::NewStub(channel)) {}

  CmdResponse TakeAPicture(int qpcrIdIn, int isStart) {

     GPRPC::TakeAPictureParam photoParam;
     ClientContext context;
     CmdResponse resp;
     if(qpcrIdIn==0)
     {
        photoParam.set_moduletype(GPRPC::ModuleType::MT_QPCR1);
     }
     else if(qpcrIdIn == 1)
     {
        photoParam.set_moduletype(GPRPC::ModuleType::MT_QPCR2);
     }
     else
     {
        resp.set_returnval(ReturnVal::RET_FALSE);
        return resp;
     }
     
     if(isStart)
     {
        photoParam.set_switch_(GPRPC::Switch::OPEN);

     }
     else
     {
        photoParam.set_switch_(GPRPC::Switch::CLOSE);
     }
     printf("in TakeAPicture, qpcrid=%d,istart:%d\n",qpcrIdIn,isStart);
     
     stub_->TakeAPicture(&context, photoParam,&resp);
     return resp;
  }

   CmdResponse HorScanCodeReport(int chanNumIn) {

     GPRPC::HorBarcodesParam barcodes;
     ClientContext context;
     CmdResponse resp;

     int scanerId = (chanNumIn>>4)&0x0f;
     int subChan = chanNumIn&0x0f;


     printf("in HorScanCodeReport, scanerId=%d,subChan:%d\n",scanerId,subChan);
     if(scanerId>3 || scanerId < 0)
     {
        std::cout<<"scanerId is not valid"<<std::endl;
        return resp;
     }

     if(subChan < 0 || subChan > 3)
     {
        std::cout<<"subChan is not valid"<<std::endl;
        return resp;
     }
     char filePath[128] = {0};

     sprintf(filePath,"%schan_%d_%d.txt",FILE_BARCODE_PATH,scanerId,subChan);
     std::ifstream fileIn(filePath);

     if(!fileIn.is_open())
     {
        std::cout<<"load file "<<filePath<<" failed"<<std::endl;
        resp.set_returnval(GPRPC::RET_FALSE);

        return resp;
     }
     
     GPRPC::HorBarcodeParam * ptrBarcodeParam = NULL; 
     char  oneBarcode[128] = {0};

      char refCode[4] = {0};
      if(scanerId == 1)
      {
         char arrRef[4] = {'D','E','D','E'};
         refCode[0] = arrRef[subChan];

         refCode[1] = '1' + subChan/2;
      }

     while(!fileIn.eof())
     {
         memset(oneBarcode,0,128);
         fileIn.getline(oneBarcode,128);
         int lenBarCode = strlen(oneBarcode);
         if(lenBarCode>0)
         {           

            std::cout<<"str:"<<oneBarcode<<std::endl;
            std::cout<<" len:"<<lenBarCode<<std::endl;

            std::string * strBarcode = new std::string(oneBarcode);
            ptrBarcodeParam = barcodes.add_barcodesparam();
            if( lenBarCode == 6 
            && refCode[0]== oneBarcode[0]
            && refCode[1]== oneBarcode[1])
            {
               ptrBarcodeParam->set_allocated_posbarcode(strBarcode);
            }
            else if(ptrBarcodeParam)
            {
               ptrBarcodeParam->set_allocated_infobarcode(strBarcode);
            }
         }

     }
     resp.set_returnval(GPRPC::ReturnVal::RET_TRUE);
     //
     fileIn.close();
     std::cout<<"file closed"<<std::endl;
     stub_->ReportHorBarcodesInfo(&context, barcodes,&resp);

     barcodes.clear_barcodesparam();
     
     return resp;
  }


   CmdResponse temperatureReport(int boardIdIn,int chanNumIn, float temperatureIn) {
     GPRPC::TempPara tempToReport;
     ClientContext context;
     CmdResponse resp;
     int pos = -1;
     int actualChan = 0;

     if(boardIdIn==QPCR_CTRL_BOARD)
     {
         if((chanNumIn - CHAN_TEMP_Q1_BASE) > (MAX_CHAN_ONE_QPCR-1) )
         {
             actualChan = chanNumIn - CHAN_TEMP_Q3_BASE;
             if(actualChan >= 0 && actualChan < MAX_CHAN_ONE_QPCR)
             {
                
               int needReportNow = procQpcrTempReport(0,actualChan,temperatureIn,qpcrTempArr);
                
               if(needReportNow)
               {
                  std::cout<<"report qpcr0 temp now"<<std::endl;
                   GPRPC::QpcrTempParam qpcrTempParam;
                   qpcrTempParam.set_module(GPRPC::MT_QPCR1);
                   qpcrTempParam.set_targettemp(qpcrTempArr[0]);
                   qpcrTempParam.set_heatlidtemp(qpcrTempArr[1]);
                   qpcrTempParam.set_metalbath1temp(qpcrTempArr[2]);
                   qpcrTempParam.set_metalbath2temp(qpcrTempArr[3]);
                   qpcrTempParam.set_metalbath3temp(qpcrTempArr[4]);
                   qpcrTempParam.set_metalbath4temp(qpcrTempArr[5]);
                   qpcrTempParam.set_metalbath5temp(qpcrTempArr[6]);
                   stub_->ReportQpcrTemp(&context,qpcrTempParam,&resp);
                   return  resp;                  
               }
             }
             
             resp.set_returnval(GPRPC::ReturnVal::RET_TRUE);
             return resp;
         }
     }

     if(boardIdIn==QPCR_CTRL_BOARD_1)
     {
         if((chanNumIn - CHAN_TEMP_Q2_BASE) > (MAX_CHAN_ONE_QPCR-1) )
         {
             actualChan = chanNumIn - CHAN_TEMP_Q4_BASE;
             if(actualChan >= 0 && actualChan < MAX_CHAN_ONE_QPCR)
             {
               int needReportNow = procQpcrTempReport(1,actualChan,temperatureIn,qpcr1TempArr);
               
               if(needReportNow)
               {
                  std::cout<<"report qpcr1 temp now"<<std::endl;
                   GPRPC::QpcrTempParam qpcrTempParam;
                   qpcrTempParam.set_module(GPRPC::MT_QPCR1);
                   qpcrTempParam.set_targettemp(qpcr1TempArr[0]);
                   qpcrTempParam.set_heatlidtemp(qpcr1TempArr[1]);
                   qpcrTempParam.set_metalbath1temp(qpcr1TempArr[2]);
                   qpcrTempParam.set_metalbath2temp(qpcr1TempArr[3]);
                   qpcrTempParam.set_metalbath3temp(qpcr1TempArr[4]);
                   qpcrTempParam.set_metalbath4temp(qpcr1TempArr[5]);
                   qpcrTempParam.set_metalbath5temp(qpcr1TempArr[6]);
                   stub_->ReportQpcrTemp(&context,qpcrTempParam,&resp);
                   return resp;                   
               }
             }
             
             resp.set_returnval(GPRPC::ReturnVal::RET_TRUE);
             return resp;
         }
     }

     switch(boardIdIn)
     {
        case THERMAL_SEAL_BOARD:
        {
            pos = GPRPC::TP_SEAL + chanNumIn - CHAN_TEMP_SEAL_BASE;
        }
        break;
        case PURIFICATION_BOARD:
        {
            pos = GPRPC::TP_SHAKE1 + chanNumIn - CHAN_TEMP_SHAKE_BASE;
        }
        break;
        case QPCR_CTRL_BOARD:
        {
            pos = GPRPC::TP_BATH1_1 + chanNumIn - CHAN_TEMP_Q1_BASE;
        }
        break;
        case QPCR_CTRL_BOARD_1:
        {
           pos = GPRPC::TP_BATH1_2 + chanNumIn - CHAN_TEMP_Q2_BASE;
        }
        break;
        default:
        break;
     }

     tempToReport.set_tempos(GPRPC::TempPos(pos));

     tempToReport.set_temp(temperatureIn);
     std::cout<<"report temp grpc now"<<std::endl;
     stub_->ReportTemp(&context,tempToReport,&resp);

     return resp;

   }

 private:
  std::unique_ptr<CtrlSysService::Stub> stub_;
};



void procPhotoNotify(void)
{
      CmdResponse reply;
      std::shared_ptr<::grpc::Channel> channelReport = 
      grpc::CreateChannel(REPORT_IP_PORT, grpc::InsecureChannelCredentials());
    
      // if(GRPC_CHANNEL_READY != channelReport->GetState(1))
      // {
      //    std::cout<<"create channel for grpc failed"<<std::endl;
      //   return; 
      // } 
     
      CtrlSysServiceClient stClientCtl(channelReport); 
      reply = stClientCtl.TakeAPicture(0,1);

      if(reply.returnval() == ReturnVal::RET_TRUE)
      {
         std::cout<<"notify take photo success\n"<<std::endl;
      }
      else
      {
         std::cout<<"notify take photo failed\n"<<std::endl;
      }
}


void procScancodeNotify(int scanChan)
{
      CmdResponse reply;
      std::shared_ptr<::grpc::Channel> channelReport = 
      grpc::CreateChannel(REPORT_IP_PORT, grpc::InsecureChannelCredentials());
    
      // if(GRPC_CHANNEL_READY != channelReport->GetState(1))
      // {
      //    std::cout<<"create channel for grpc failed"<<std::endl;
      //   return; 
      // } 
     
      CtrlSysServiceClient stClientCtl(channelReport);


      reply = stClientCtl.HorScanCodeReport(scanChan);

      if(reply.returnval() == ReturnVal::RET_TRUE)
      {
         std::cout<<"notify barcode success\n"<<std::endl;
      }
      else
      {
         std::cout<<"notify barcode failed\n"<<std::endl;
      }
}



void procReportMsg(int dataLen, char * dataIn)
{
  if(dataLen<sizeof(int)*2)
  {
    return;
  }
  report_up_msg reportMsg;
  int currOffset = 0;

  CmdResponse reply;

  memcpy(&reportMsg.type,dataIn,sizeof(int));
  currOffset += sizeof(int);

  memcpy(&reportMsg.dataLen,dataIn+currOffset,sizeof(int));
  currOffset += sizeof(int);

  std::cout<<"lenAll:"<<dataLen<<",type:"<<reportMsg.type<<",len:"<<reportMsg.dataLen<<std::endl;
  
  if(reportMsg.type == NOTIFY_DJCLEAN_WATER_LESS)
  {

  }
  else if(reportMsg.type == NOTIFY_SCAN_CODE)
  {
    memcpy(&reportMsg.un_msg_data.barcodeChan,dataIn+currOffset,sizeof(int));
    currOffset += sizeof(int);

    //printf("barcode of chan%d received\n",reportMsg.un_msg_data.barcodeChan);

    procScancodeNotify(reportMsg.un_msg_data.barcodeChan);
  }
  else if(reportMsg.type == NOTIFY_QPCR_PHOTO)
  {
      int qpcrNodifyData = 0;

      memcpy(&qpcrNodifyData,dataIn+currOffset,sizeof(int));

      int qpcrId = qpcrNodifyData&0x0000ffff;

      int isStart = (qpcrNodifyData>>16)&0x0000ffff;

      std::cout<<"QPCR,id:"<<qpcrId<<",isStart:"<< isStart <<std::endl;
      
      std::shared_ptr<::grpc::Channel> channelReport = 
      grpc::CreateChannel(REPORT_IP_PORT, grpc::InsecureChannelCredentials());
    
    // if(GRPC_CHANNEL_READY != channelReport->GetState(1))
    // {
    //   std::cout<<"create channel for grpc failed"<<std::endl;
    //   return; 
    // } 
     
      CtrlSysServiceClient stClientCtl(channelReport); 
      reply = stClientCtl.TakeAPicture(qpcrId,isStart);

      if(reply.returnval() == ReturnVal::RET_TRUE)
      {
         std::cout<<"notify take photo success\n"<<std::endl;
      }
      else
      {
         std::cout<<"notify take photo failed\n"<<std::endl;
      }
  }
  else if(reportMsg.type == NOTIFY_CURR_TEMP)
  {
      temp_report_msg tempReportMsg;
      memcpy(&tempReportMsg,dataIn+currOffset,sizeof(temp_report_msg));  

      printf("baordId:%d,chan%d,temp:%f\n",tempReportMsg.boardId,tempReportMsg.chanNum,tempReportMsg.currTemp);
      std::shared_ptr<::grpc::Channel> channelReport = 
      grpc::CreateChannel(REPORT_IP_PORT, grpc::InsecureChannelCredentials());
      CtrlSysServiceClient stClientCtl(channelReport); 
      reply = stClientCtl.temperatureReport(tempReportMsg.boardId,tempReportMsg.chanNum,tempReportMsg.currTemp);      
      
      if(reply.returnval() == ReturnVal::RET_TRUE)
      {
         std::cout<<"notify temperature success\n"<<std::endl;
      }
      else
      {
         std::cout<<"notify temperature failed\n"<<std::endl;
      }
  }
  
}
